home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
ddjcompr
/
hstest
/
src
/
pack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-28
|
9KB
|
376 lines
//************************************************************************
// PACK.C
// Modul zur Datenkomprimierung
// Idee und Implementierung tom ehlert '90
//
// Datenaufzeichnungsformat
//
// die Idee die dahintersteckt funktioniert wie folgt :
// wenn der derzeitige String bereits gesendet worden ist, kodiere
// ihn als kombination von index,laenge in die bereits empfangenen Daten
// als 2-Bytekombination.
//
// Das genaue Format ist wohl am besten durch UNPACK beschrieben, man
// macht dann auch keine Fehler in der Dokumentation.
//
// Das Schema laeuft wie folgt :
//
// Das jeweils erste Byte decodiert 8 Gruppen. Bit 7 (0x80) decodiert
// die erste Gruppe,Bit 6 (0x40) die zweite usf. . Dabei gilt :
// Bit == 0 --> Gruppe besteht aus 1 Byte, dieses ist in den
// Zielpuffer zu kopieren.
// Bit == 1 --> Gruppe besteht aus komprimierter Information,
// lese zwei Byte.
//
// index = *pbuffer & SENDLEN (0x3ff);
// length = (*pbuffer >> 12) + MIN_LENGTH;
// if (length == 0x0f+MIN_LENGTH)
// length = pbuffer[2]; /* code is 3 bytes */
//
// memcpy(outbuffer,outbuffer-index,length);
//
//
//
//************************************************************************
#include <stdio.h>
#include <setjmp.h>
#include "pack.h"
#include "huffman.h"
typedef unsigned char uchar;
#ifdef MSDOS
#define ONLY_ON_80x86 /* this is ok */
#else
#define ONLY_ON_80x86 this runs only on 80x86 // BYTE - ORDER !!
#endif
#define MIN_LENGTH 3 /* minimum to be compressed */
#define MAXCODELENGTH 0x0f
#define IBSIZE 0xff
#define SENDLEN 0xfff /* MUST BE 00001111111 */
# define CRBLEN 0x800
# define BUFFTAIL (SENDLEN+1)
# define BUFFOVER 0x100
#ifdef PACK
static uchar sendbuff[ CRBLEN+BUFFTAIL+BUFFOVER] = {0};
static int offset1 [1+CRBLEN+BUFFTAIL+BUFFOVER] = {0xffff,0};
#define offset (offset1+1)
#define NVH 0xffff
//
// Die gewaehlte HASH-Function ist beliebig; sie returned einen
// Wert 0..HASH_SIZE. die vorgeschlagene bietet einen Kompromiss
// zwischen sizeof(last(HASH_SIZE)) und Geschwindigkeit, diese
// wird dadurch aber nicht wesentlich verringert
//
#define HASH_SIZE (0x400+0x200+0x100) // (0xff<<2) + (0xff<<1) + 0xff) ??
#define HASH_VAL(ptr) ((ptr)[0] + ((ptr)[1]<<1) + ((ptr)[2] << 2))
static int last[HASH_SIZE] = {0};
#define add_list( c, cptr) offset[cptr] = last[c],last[c] = (cptr)
/**********************************************************************
** output buffer waehrend des packens
*/
static uchar far *packptr = NULL;
static uchar far *packend = NULL;
static uchar far *ibuffer = NULL;
static unsigned short ilen = 0;
static jmp_buf not_packable = {0};
static uchar packmask = 0;
static uchar packmaskbit = 0;
static uchar far *packmaskptr = NULL;
static int tosend = 0;
static int gesendet = 0;
#define STATIC
STATIC void new_mask(void);
STATIC void send1(void);
STATIC void send(int len);
STATIC void move_buffers(void);
STATIC int xlen(void);
STATIC void crunch(void);
STATIC int rdf(unsigned char *d,unsigned len);
extern int _fastcall memid(uchar *s1,uchar *s2);
STATIC void new_mask(void)
{
*packmaskptr = packmask;
packmaskptr = packptr++;
packmaskbit = 0x80;
packmask = 0x00;
if (packptr >= packend)
longjmp(not_packable,1);
}
STATIC void move_buffers(void)
{
register int *ip, loop,rd;
memcpy(sendbuff,sendbuff+CRBLEN,BUFFTAIL+BUFFOVER);
memcpy((uchar*)offset ,(uchar*)(offset +CRBLEN),
sizeof(offset[0])*(BUFFTAIL+BUFFOVER));
gesendet -= CRBLEN;
tosend -= CRBLEN;
while ((rd = rdf(sendbuff+tosend,sizeof(sendbuff)-tosend)) > 0)
tosend += rd;
for (ip = last,loop = LENGTH(last);loop ;ip++,--loop)
if (*ip >= 0)
*ip -= CRBLEN;
for (ip = offset,loop = BUFFTAIL+BUFFOVER;loop ;ip++,--loop)
if (*ip >= 0)
*ip -= CRBLEN;
}
STATIC void crunch(void)
{
register int len,tbs,find_index;
while ((tbs = tosend - gesendet) > 0)
{
//**********************************************************************
// this part is essentially a subroutine, calculating len & find_index
//**********************************************************************
{
register int sp;
register int stop_ptr;
register uchar *sbcheck;
register short ccheck;
register uchar *tbs = sendbuff + gesendet;
register int loop;
len = MIN_LENGTH-1;
stop_ptr = gesendet - SENDLEN;
if (stop_ptr < 0)
stop_ptr = 0;
ccheck = *(int*)(tbs+1);
sbcheck = sendbuff+1;
for (sp = last[HASH_VAL(tbs)];sp >= stop_ptr;sp = offset[sp])
{
if (*(short *)(sbcheck+sp) == ccheck)
if ((loop = memid(sendbuff+sp,tbs)) > len)
{
len = loop;
ccheck = *(short *)(tbs+len-1);
sbcheck = sendbuff+len-1;
find_index = gesendet - sp;
if (len >= IBSIZE)
break;
}
}
}
len = min(len,255);
len = min(len,tbs);
if (len >= MIN_LENGTH)
//**********************************************************************
// another inlined subroutine :
// write len + index
//**********************************************************************
{
register int index;register uchar *ibp;
ONLY_ON_80x86;
if (len < MAXCODELENGTH+MIN_LENGTH)
{ // remember : findindex <= SENDLEN !!
*((int far *)packptr)++ = find_index | ((len -MIN_LENGTH) << 12) ;
}
else
{
*((int far *)packptr)++ = find_index | (MAXCODELENGTH << 12) ;
*packptr++ = (uchar)len;
}
packmask |= packmaskbit;
if ((packmaskbit >>= 1) == 0)
new_mask();
ibp = sendbuff+gesendet-1,index=gesendet-1;
gesendet += len;
for ( ; len ; ibp++,index++, --len)
{
register int hval = HASH_VAL(ibp);
add_list(hval,index);
}
}
else
//**********************************************************************
// another inlined subroutine :
// write literal character
//**********************************************************************
{
register uchar *s = sendbuff+gesendet; /* zu sendenden */
register int hval;
*packptr++ = *s++;
if ((packmaskbit >>= 1) == 0)
new_mask();
hval = HASH_VAL(s-2);
add_list(hval,gesendet-1);
gesendet++;
if (gesendet > CRBLEN +BUFFTAIL )
move_buffers();
}
if (gesendet > CRBLEN +BUFFTAIL )
move_buffers();
}
}
STATIC int rdf(uchar *d,unsigned len)
{
len = min(len,ilen);
memcpy(d,ibuffer,len);
ilen -= len;
ibuffer += len;
return len;
}
int far _loadds pack(pbuffer,pbufferlen,inbuffer,blen)
uchar far *pbuffer;short pbufferlen;
uchar far *inbuffer;short blen;
{
int huff_length;
if (blen == 0 || setjmp(not_packable))
return 0xffff;
ilen = blen;
ibuffer = inbuffer;
/* wenn man die naechsten zwei zeilen vertauscht */
/* und -e eingeschaltet ist verhakelt sich MSC 6.00 */
packend = pbuffer + pbufferlen - 25;
packptr = pbuffer;
if (packptr >= packend)
longjmp(not_packable,1);
packmaskptr = packptr++;
packmaskbit = 0x80;
packmask = 0x00;
tosend = rdf(sendbuff,CRBLEN+BUFFTAIL+BUFFOVER);
gesendet = 0;
memset(last ,NVH,sizeof(last));
memset(offset1,NVH,min(sizeof(offset1) , blen));
gesendet = 0;
crunch();
*packmaskptr = packmask;
if (packmaskbit == 0x80) // letztes newmask() zuviel
packptr--;
return packptr - pbuffer;
}
#endif
#ifdef UNPACKC
//*********************************************************************
// this is the uncrunching part
// unpackc() is written in C
// unpack() see UNPACK.ASM
// both routines work identical
//*********************************************************************
int far _loadds unpackc(outbuffer,pbuffer,packlen)
uchar far *outbuffer;
uchar far *pbuffer;register int packlen;
{
register int uloop;
register uchar packmask;
int length;unsigned index;
uchar far *sbuffer = outbuffer;
for (uloop = 1;packlen > 0;packmask <<= 1)
{
if (--uloop == 0)
{
packmask = *pbuffer++,packlen--;
uloop = 8;
}
if ((packmask & 0x80) == 0) /* this byte is literally */
*outbuffer++ = *pbuffer++,packlen--;
else
{ /* next 2 bytes coded */
ONLY_ON_80x86;
index = *(int far *)pbuffer; /* 4 bit length */
length = (index >> 12) + MIN_LENGTH;/* 12 bit offset */
index &= SENDLEN;
if (length == MAXCODELENGTH+MIN_LENGTH) /* length > 18 */
{ /* use next byte for length*/
length = pbuffer[2]; /* code is 3 bytes */
pbuffer += 3;
packlen -= 3;
}
else {
packlen -= 2;
pbuffer += 2;
}
/* copy BYTEWISE with OVERWRITE */
if (index == 1) // memcpy will not work as it copies WORDS
memset(outbuffer,*(outbuffer-1),length);
else
memcpy(outbuffer,outbuffer-index,length);
outbuffer += length;
}
}
return outbuffer-sbuffer;
}
#endif
//***********************************************************************
// externe Assmblerroutinen :
//
// memidc(uchar *dest,uchar *src)
// // return number of equal bytes
// {
// register uchar *dr = dest;
//
// for (; *src++ == *dr ;dr++)
// ;
// return dr-dest;
// }
//***********************************************************************